package tjs.study.notes.jvm.clash.dotest;

import tjs.study.notes.jvm.clasha.DoTestOfClasha;
import tjs.study.notes.jvm.clashb.DoTestOfClashb;
import tjs.study.notes.jvm.utils.VersionObj;
import tjs.study.notes.jvm.utils.jarClash.JarClashStarter;

/**
 * Created by Nicky.Tang on 2021/10/19 10:42 上午
 *
 * @since 02.12.10
 */
public class DoTestOfClashc {
    final static String pathPre = "/Users/piangpiang/Documents/software/apache-maven-3.6.1/my_maven_ws/TJS/study/notes";

    public static void main(String[] args) throws Exception {
        // 配置某个类，以及其相关版本的jar
        JarClashStarter.addOneClashJar("tjs.study.notes.jvm.clashb.DoTestOfClashb",
                pathPre + "/jvm-clash-b/0.0.1-SNAPSHOT/jvm-clash-b-0.0.1-SNAPSHOT.jar",
                pathPre + "/jvm-utils/v2.0/jvm-utils-v2.0.jar"
        );
        // 重新调用main方法，使用自定义的类加载器拦截所有类的加载
        JarClashStarter.trustStart(DoTestOfClashc.class, args);

//        printClassLoader();

//         testVersionObj();
//         testNoReturn();
        testHasReturn();
    }

    public static void testNoReturn() {
        DoTestOfClasha doTestOfClasha = new DoTestOfClasha();
        doTestOfClasha.doSomethingA();
        System.out.println("doTestOfClasha: " + doTestOfClasha.getClass().getClassLoader());//AppClassLoader

        DoTestOfClashb doTestOfClashb = new DoTestOfClashb();
        doTestOfClashb.doSomethingB();
        System.out.println("doTestOfClashb: " + doTestOfClashb.getClass().getClassLoader());//ModuleSelfClassLoader
    }

    public static void testHasReturn() throws Exception {
        DoTestOfClasha doTestOfClasha = new DoTestOfClasha();
        doTestOfClasha.doSomethingARetObj();
        /**
         * 执行完此行代码，jvm已经使用AppClassLoader加载了VersionObj
         */
        VersionObj versionObjecta = doTestOfClasha.doSomethingARet();
        System.out.println("versionObjecta: " + versionObjecta.getClass().getClassLoader());//AppClassLoader
        //DoTestOfClasha.class.getDeclaredMethod("doSomethingARet1").invoke(doTestOfClasha);

        DoTestOfClashb doTestOfClashb = new DoTestOfClashb();
        doTestOfClashb.doSomethingBRetObj();
        /**
         * 执行完此行代码等号右边doTestOfClashb.doSomethingBRet()，ModuleSelfClassLoader会再次加载VersionObj
         * 导致，ModuleSelfClassLoader.VersionObj != AppClassLoader.VersionObj
         * 解决方案：
         * 1. 反射调用,并用Object接收
         * 2. 控制目标类VersionObj全局只用一个类加载器加载一次
         */
        //VersionObj versionObjectB = doTestOfClashb.doSomethingBRet();
        //System.out.println("versionObjecta: " + versionObjectB.getClass().getClassLoader());//java.lang.LinkageError
        Object versionObjectBReflect = DoTestOfClashb.class.getDeclaredMethod("doSomethingBRet").invoke(doTestOfClashb);
        System.out.println("versionObjectBReflect: " + versionObjectBReflect.getClass().getClassLoader());//ModuleSelfClassLoader
    }


    public static void printClassLoader() {
        System.out.println("DoTestOfClasha: " + DoTestOfClasha.class.getClassLoader());//AppClassLoader
        System.out.println("DoTestOfClashb: " + DoTestOfClashb.class.getClassLoader());//ModuleSelfClassLoader
        System.out.println("DoTestOfClashc: " + DoTestOfClashc.class.getClassLoader());//JarClashClassLoader
    }
}
